/* Copyright  2009
   @Author
   Richard Changde Yin            e-mail yinchangde@hotmail.com

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; version 2 of the License.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

/**
 * @filename: mm_handler.h
 */



/* class for the the main memory handler */

#ifndef __MM_HANDLER_H__
#define __MM_HANDLER_H__

#include <handler.h>
#include <thr_lock.h>



class CFIELD ;

typedef struct st_mmhlder_info
{
  uint32_t records;          /* Records in database */
  uint32_t deleted;          /* Deleted records in database */
  uint32_t max_records;
  uint64_t data_length;
  uint64_t index_length;
  uint32_t reclength;         /* Length of one record */
  int      errkey;
  uint64_t auto_increment;
} MMHANDLERINFO;

class BUCKET_TREE_ELEMENT;
typedef struct st_mm_info
{
  char*          table_alias;
  unsigned char *current_ptr;
  uint32_t current_record,next_block;
  int      lastinx,errkey;
  int      mode; /* Mode of file (READONLY..) */
  uint32_t opt_flag,update;
  unsigned char *lastkey; /* Last used key with rkey */
  unsigned char *recbuf;                         /* Record buffer for rb-tree keys */
  enum ha_rkey_function last_find_flag;
  BUCKET_TREE_ELEMENT *parents[MAX_TREE_HEIGHT+1];
  BUCKET_TREE_ELEMENT **last_pos;
  uint32_t      lastkey_len;
  bool          implicit_emptied;
  uint64_t      auto_increment;
  uint32_t      auto_key;
  uint32_t      auto_key_type;
  THR_LOCK_DATA lock;
  HashIndexNode* current_hIdxNode;
  MMHANDLERINFO  hlderinfo;

} MM_INFO;


typedef struct st_mm_share
{
  CFIELD   *column_defs   ;

  uint32_t min_records,max_records; /* Params to open */
  uint64_t index_length,max_table_size;
  uint32_t key_stat_version;                /* version to indicate insert/delete */
  uint32_t records;             /* Actual record (row) count */
  uint32_t blength;               /* used_chunk_count rounded up to 2^n */
  uint32_t fixed_data_length;     /* Length of record's fixed part, which contains keys and always fits into the first chunk */
  uint32_t fixed_column_count; /* Number of columns stored in fixed_data_length */
  uint32_t changed;
  uint32_t keys;
  uint32_t max_key_length;
  uint32_t column_count;
  uint32_t currently_disabled_keys;    /* saved value from "keys" when disabled */
  uint32_t open_count;


  char * name;    /* Name of "memory-file" */
  THR_LOCK lock;
  pthread_mutex_t intern_lock;      /* Locking for use with _locking */
  bool delete_on_close;
  //LIST open_list;
  uint32_t auto_key;
  uint32_t auto_key_type;           /* real type of the auto key segment */
  uint64_t auto_increment;
} MM_SHARE;



typedef struct st_mm_share MM_SHARE;

typedef unsigned char * MM_HANDLER_PTR;


class mm_handler: public handler
{
  MM_INFO *file;

  Session*      user_session ;  /* the thread handle of the user
                currently using the handle; this is
                set in external_lock function */

  key_map     btree_keys;
  /* number of records changed since last statistics update */
  uint32_t    records_changed;
  uint32_t    key_stat_version;
  bool        internal_table;
  bool        istemp_table  ;
  ulong       start_of_scan; /* this is set to 1 when we are
                              starting a table scan but have not
                              yet fetched any row, else 0 */
public:
  mm_handler(TABLE_SHARE *table);

  ~mm_handler();
  handler *clone(MEM_ROOT *mem_root);
  inline const char *table_type() const
  {
    return "Main MEMORY";
  }
  const char *index_type(uint32_t inx);

  enum row_type get_row_type() const;
  const char **bas_ext() const;
  inline uint64_t table_flags() const
  {
    return  (HA_FAST_KEY_READ
            | HA_NO_BLOBS
            | HA_NULL_IN_KEY
            | HA_BINLOG_ROW_CAPABLE
            | HA_BINLOG_STMT_CAPABLE
            | HA_REC_NOT_IN_SEQ
            | HA_HAS_RECORDS
            | HA_STATS_RECORDS_IS_EXACT
            );
  }
  uint32_t index_flags(uint32_t inx, uint32_t part, bool all_parts) const;
  inline const key_map *keys_to_use_for_scanning() { return &btree_keys; }
  inline uint32_t max_supported_keys()          const   { return MAX_KEY; }
  inline uint32_t max_supported_key_part_length() const { return MAX_KEY_LENGTH; }
  inline double scan_time()
  { return (double) (stats.records+stats.deleted) / 20.0+10; }
  inline double read_time(uint32_t, uint32_t,
                   ha_rows rows)
  { return (double) rows /  20.0+1; }

  int open(const char *name, int mode, uint32_t test_if_locked);
  int close(void);
  void set_keys_for_scanning(void);
  int write_row(unsigned char * buf);
  int update_row(const unsigned char * old_data, unsigned char * new_data);
  int delete_row(const unsigned char * buf);
  virtual void get_auto_increment(uint64_t offset, uint64_t increment,
                                  uint64_t nb_desired_values,
                                  uint64_t *first_value,
                                  uint64_t *nb_reserved_values);
  int index_read_map(unsigned char * buf,
                     const unsigned char * key,
                     key_part_map keypart_map,
                     enum ha_rkey_function find_flag);
  int index_read_last_map(unsigned char *buf, const unsigned char *key,
                          key_part_map keypart_map);
  int index_read_idx_map(unsigned char * buf, uint32_t index,
                         const unsigned char * key,
                         key_part_map keypart_map,
                         enum ha_rkey_function find_flag);
  int index_next(unsigned char * buf);
  int index_prev(unsigned char * buf);
  int index_first(unsigned char * buf);
  int index_last(unsigned char * buf);
  int index_next_same(unsigned char *, const unsigned char *, uint32_t);
  int rnd_init(bool scan);
  int rnd_next(unsigned char *buf);
  int rnd_pos(unsigned char * buf, unsigned char *pos);
  void position(const unsigned char *record);

  int mm_scan_init(MM_INFO *info) ;
  int info(uint);

  int extra(enum ha_extra_function operation);

  int reset();

  int external_lock(Session *session, int lock_type);

  int delete_all_rows(void);

  int disable_indexes(uint32_t mode);

  int enable_indexes(uint32_t mode);

  int indexes_are_disabled(void);

  ha_rows records_in_range(uint32_t inx,
                           key_range *min_key,
                           key_range *max_key);

  int delete_table(const char *from);

  int drop_table(const char *name);

  int rename_table(const char * from, const char * to);

  int create(const char *name, Table *form, HA_CREATE_INFO *create_info);

  void update_create_info(HA_CREATE_INFO *create_info);

  THR_LOCK_DATA **store_lock(Session *session, THR_LOCK_DATA **to,
                             enum thr_lock_type lock_type);

  int cmp_ref(const unsigned char *ref1, const unsigned char *ref2);

  bool check_if_incompatible_data(HA_CREATE_INFO *info, uint32_t table_changes);
private:
  void update_key_stats();
protected:

  friend class DatabaseManagerImpl;
};

#endif /* __MM_HANDLER_H__ */
